﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using MediaPortal.GUI.Library;
using MediaPortal.Dialogs;
using System.Timers;
using System.Windows.Forms;
using System.IO;

namespace MPNotificationBar
{
    public static class NotificationBarManager
    {
        public delegate void NotificationAdded(INotification iNotification);
        public static event NotificationAdded OnNotificationAdded;
        public delegate void NotificationRemoved(INotification iNotification);
        public static event NotificationRemoved OnNotificationRemoved;
        static List<INotification> _Notifications = new List<INotification>();
        static int _LastNotificationID = 0;

        public enum Types
        {
            Information,
            Warning
        }

        public static void AddNotification(INotification iNotification)
        {
            //Set notification id
            iNotification.NotificationID = ++_LastNotificationID;

            _Notifications.Add(iNotification);
            if (OnNotificationAdded != null) OnNotificationAdded(iNotification);
        }

        public static INotification AddNotification(int PluginID, string Text, NotificationBarManager.Types NotificationType)
        {
            var notification = new Notification(PluginID, Text, NotificationType);

            AddNotification(notification);

            return notification;
        }

        public static INotification AddNotification(int PluginID, string Text, NotificationBarManager.Types NotificationType, Boolean NeedsProgressBar)
        {
            var notification = new Notification(PluginID, Text, NotificationType, NeedsProgressBar);

            AddNotification(notification);

            return notification;
        }

        public static INotification AddNotification(int PluginID, string Text, NotificationBarManager.Types NotificationType, Boolean NeedsProgressBar, Boolean ShowInFullScreen)
        {
            var notification = new Notification(PluginID, Text, NotificationType, NeedsProgressBar, ShowInFullScreen);

            AddNotification(notification);

            return notification;
        }

        public static INotification AddNotification(int PluginID, string Text, string SubText, string ThumbnailPath, int SecondsToLive, NotificationBarManager.Types NotificationType, Boolean NeedsProgressBar, Boolean ShowInFullScreen)
        {
            var notification = new Notification(PluginID, Text, SubText, ThumbnailPath, SecondsToLive, NotificationType, NeedsProgressBar, ShowInFullScreen);

            AddNotification(notification);

            return notification;
        }

        public static void RemoveNotification(INotification iNotification)
        {
            _Notifications.Remove(iNotification);
            try
            {
                OnNotificationRemoved(iNotification);
            }
            catch { }
        }

        public static List<INotification> Notifications
        {
            get { return _Notifications; }
        }
    }

    public class GUIManager : GUIInternalOverlayWindow, ISetupForm, IRenderLayer
    {
        const int _windowID = 99207; // WindowID of windowplugin belonging to this setup. Enter your own unique code

        [SkinControl(1)]
        protected GUIImage _NotificationImage;
        [SkinControl(2)]
        protected GUILabelControl _Text;
        [SkinControl(3)]
        protected GUITextControl _SubText;
        System.Timers.Timer _UpdateTimer = new System.Timers.Timer();
        Double _UpdateTimerNotificationInterval = 6000; //6 sec
        private DateTime _updateTime = DateTime.Now;
        private bool _lastStatus = false;
        private bool _didRenderLastTime = false;
        private bool _showBar = false;
        private static short _ShowNumber = 0;
        private static short _LastShowNumber = -1;
        private Boolean _SkinSupported = false;
        private String _PreviousSkin = "";

        string skinFolderPath;

        public GUIManager()
        {
            NotificationBarManager.OnNotificationAdded += new NotificationBarManager.NotificationAdded(NotificationBarManager_OnNotificationAdded);
        }

        void NotificationBarManager_OnNotificationAdded(INotification iNotification)
        {
            iNotification.ProgressChanged += new EventHandler(iNotification_ProgressChanged);
            iNotification.ContentChanged += new EventHandler(iNotification_ContentChanged);

            if (NotificationBarManager.Notifications.Count == 1)
            {
                _showBar = true;
                //Wait for the Render roundtrip
                System.Threading.Thread.Sleep(1000);
                //Show notification
                SwitchNotification();
            }
        }

        void _UpdateTimer_Elapsed(object sender, ElapsedEventArgs e2)
        {
            if (NotificationBarManager.Notifications.Count > 0)
            {
                SwitchNotification();
            }
            else
            {
                _showBar = false;
            }
        }

        void iNotification_ProgressChanged(object sender, EventArgs e)
        {
            var notification = sender as INotification;
            if (NotificationBarManager.Notifications[_ShowNumber].PluginID == notification.PluginID)
                UpdateContent();
        }

        void iNotification_ContentChanged(object sender, EventArgs e)
        {
            var notification = sender as INotification;
            if (NotificationBarManager.Notifications[_ShowNumber].PluginID == notification.PluginID)
                UpdateContent();
        }

        private void SwitchNotification()
        {
            _ShowNumber++;
            if (_ShowNumber >= NotificationBarManager.Notifications.Count)
                _ShowNumber = 0;

            //If FullScreen mode, only show notifications with override set
            if (GUIGraphicsContext.IsFullScreenVideo && NotificationBarManager.Notifications.Where(i => i.ShowInFullScreen).Count() > 0)
            {
                Boolean _Found = false;

                //Check last part of the notification array for a match
                for (int i = _ShowNumber; i < NotificationBarManager.Notifications.Count; i++)
                {
                    if (NotificationBarManager.Notifications[i].ShowInFullScreen)
                    {
                        _ShowNumber = (short)i;
                        _Found = true;
                        break;
                    }
                }

                //If not found in the last part of the notification array
                if (!_Found)
                {
                    //Check first part of the notification array for a match
                    for (int i = 0; i < _ShowNumber; i++)
                    {
                        if (NotificationBarManager.Notifications[i].ShowInFullScreen)
                        {
                            _ShowNumber = (short)i;
                            break;
                        }
                    }
                }
            }

            if (_ShowNumber != _LastShowNumber)
            {
                _NotificationImage.Visible = false;
                _Text.Visible = false;
                _SubText.Visible = false;
            }

            UpdateContent();

            if (_showBar == false)
                _showBar = true;

            _NotificationImage.Visible = true;
            _Text.Visible = true;
            if (NotificationBarManager.Notifications[_ShowNumber].SubText.Length > 0)
                _SubText.Visible = true;

            _LastShowNumber = _ShowNumber;

            if (NotificationBarManager.Notifications[_ShowNumber].Remove)
                NotificationBarManager.RemoveNotification(NotificationBarManager.Notifications[_ShowNumber]);
        }

        private void UpdateContent()
        {
            //Set thumbnail
            if (NotificationBarManager.Notifications[_ShowNumber].ThumbnailPath.Length > 0)
                _NotificationImage.FileName = NotificationBarManager.Notifications[_ShowNumber].ThumbnailPath;
            else
            {
                skinFolderPath = String.Format(@"{0}\media\NotificationBar\", GUIGraphicsContext.Skin);

                if (NotificationBarManager.Notifications[_ShowNumber].NotificationType == NotificationBarManager.Types.Warning)
                    _NotificationImage.FileName = System.IO.Path.Combine(skinFolderPath, "Warning.png");
                else
                    _NotificationImage.FileName = System.IO.Path.Combine(skinFolderPath, "Notification.png");
            }

            //Set text labels
            _Text.Label = NotificationBarManager.Notifications[_ShowNumber].Text;
            _SubText.Label = NotificationBarManager.Notifications[_ShowNumber].SubText;

            //Set progressbar
            if (NotificationBarManager.Notifications[_ShowNumber].IsUsingProgressBar)
            {
                _Text.Label += " (" + NotificationBarManager.Notifications[_ShowNumber].Progress + "%)";
            }
        }

        #region ISetupForm Members
        // Returns the name of the plugin which is shown in the plugin menu
        public string PluginName()
        {
            return "MPNotificationBar";
        }

        // Returns the description of the plugin is shown in the plugin menu
        public string Description()
        {
            return "MP Notification Bar";
        }

        // Returns the author of the plugin which is shown in the plugin menu
        public string Author()
        {
            return "GetWell";
        }

        // show the setup dialog
        public void ShowPlugin()
        {
            MessageBox.Show("Nothing to configure");
        }

        // Indicates whether plugin can be enabled/disabled
        public bool CanEnable()
        {
            return true;
        }

        // Get Windows-ID
        public int GetWindowId()
        {
            return _windowID;
        }

        // Indicates if plugin is enabled by default;
        public bool DefaultEnabled()
        {
            return true;
        }

        // indicates if a plugin has it's own setup screen
        public bool HasSetup()
        {
            return false;
        }

        /// <summary>
        /// If the plugin should have it's own button on the main menu of MediaPortal then it
        /// should return true to this method, otherwise if it should not be on home
        /// it should return false
        /// </summary>
        /// <param name="strButtonText">text the button should have</param>
        /// <param name="strButtonImage">image for the button, or empty for default</param>
        /// <param name="strButtonImageFocus">image for the button, or empty for default</param>
        /// <param name="strPictureImage">subpicture for the button or empty for none</param>
        /// <returns>true : plugin needs it's own button on home
        /// false : plugin does not need it's own button on home</returns>
        /// 
        public bool GetHome(out string strButtonText, out string strButtonImage,
            out string strButtonImageFocus, out string strPictureImage)
        {
            strButtonText = String.Empty;
            strButtonImage = String.Empty;
            strButtonImageFocus = String.Empty;
            strPictureImage = String.Empty;
            return false;
        }

        // With GetID it will be an window-plugin / otherwise a process-plugin
        public override int GetID
        {
            get
            {
                return _windowID;
            }

            set
            {
            }
        }

        #endregion

        #region GUI control

        public override bool Init()
        {
            bool bResult = false;

            //Setup Timer
            _UpdateTimer.Interval = _UpdateTimerNotificationInterval;
            _UpdateTimer.Elapsed += new ElapsedEventHandler(_UpdateTimer_Elapsed);
            _UpdateTimer.AutoReset = true;

            GUIWindowManager.OnDeActivateWindow += new GUIWindowManager.WindowActivationHandler(GUIWindowManager_OnWindowChanged);
            GUIWindowManager.OnActivateWindow += new GUIWindowManager.WindowActivationHandler(GUIWindowManager_OnWindowChanged);
            _PreviousSkin = GUIGraphicsContext.Skin;

            if (File.Exists(GUIGraphicsContext.Skin + @"\NotificationBar.xml"))
            {
                bResult = Load(GUIGraphicsContext.Skin + @"\NotificationBar.xml");
                GUILayerManager.RegisterLayer(this, GUILayerManager.LayerType.TopOverlay);
                _SkinSupported = true;
                _UpdateTimer.Enabled = true;
            }
            else
            {
                _UpdateTimer.Enabled = false;
                _SkinSupported = false;
                _showBar = false;
                GUILayerManager.UnRegisterLayer(this);
            }

            Generals.NotificationBarGenerals _NootificationBarGenerals = new Generals.NotificationBarGenerals();

            return bResult;
        }

        void GUIWindowManager_OnWindowChanged(int windowId)
        {
            if (GUIGraphicsContext.Skin != _PreviousSkin)
            {
                _PreviousSkin = GUIGraphicsContext.Skin;
                if (File.Exists(GUIGraphicsContext.Skin + @"\NotificationBar.xml"))
                {
                    Load(GUIGraphicsContext.Skin + @"\NotificationBar.xml");
                    GUILayerManager.RegisterLayer(this, GUILayerManager.LayerType.TopOverlay);
                    _showBar = true;
                    _SkinSupported = true;
                    _UpdateTimer.Enabled = true;
                }
                else
                {
                    _UpdateTimer.Enabled = false;
                    _SkinSupported = false;
                    _showBar = false;
                    GUILayerManager.UnRegisterLayer(this);
                }
            }
        }

        //public override void DeInit()
        //{
        //    _UpdateTimer.Enabled = false;

        //    GUIWindowManager.OnDeActivateWindow -= new GUIWindowManager.WindowActivationHandler(GUIWindowManager_OnActivateWindowChanged);
        //    GUIWindowManager.OnActivateWindow -= new GUIWindowManager.WindowActivationHandler(GUIWindowManager_OnActivateWindowChanged);

        //    base.DeInit();
        //}

        private bool ShouldShowNotificationBar()
        {
            if (GUIGraphicsContext.IsFullScreenVideo)
            {
                if (NotificationBarManager.Notifications.Count > 0 && NotificationBarManager.Notifications[_ShowNumber].ShowInFullScreen)
                    return true;
                else
                    return false;
            }
            else
                return true;
        }

        public override void PreInit()
        {
            base.PreInit();
            AllocResources();
        }

        public override bool SupportsDelayedLoad
        {
            get { return false; }
        }

        private void OnUpdateState(bool render)
        {
            if (_didRenderLastTime != render)
            {
                _didRenderLastTime = render;
                if (render)
                {
                    QueueAnimation(AnimationType.Visible);
                }
                else
                {
                    QueueAnimation(AnimationType.Hidden);
                }
            }
        }

        public bool ShouldRenderLayer()
        {
            if (!ShouldShowNotificationBar())
            {
                return false;
            }

            TimeSpan ts = DateTime.Now - _updateTime;
            if (ts.TotalMilliseconds < 1000)
            {
                if (!_lastStatus)
                {
                    return base.IsAnimating(AnimationType.Hidden);
                }
                else
                {
                    return _lastStatus;
                }
            }

            _lastStatus = _showBar;

            _updateTime = DateTime.Now;
            OnUpdateState(_lastStatus);
            if (!_lastStatus)
            {
                return base.IsAnimating(AnimationType.Hidden);
            }
            else
            {
                return _lastStatus;
            }
        }

        public void RenderLayer(float timePassed)
        {
            if (!ShouldShowNotificationBar())
            {
                return;
            }
            Render(timePassed);
        }

        #endregion
    }
}
